package com.kdg.juc;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

/**
 * Created by kong on 2017/7/26.
 * 闭锁:在完成某些运算时.只有在其他所有县城的运算全部完成,当前运算才算完成
 * CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。
 */
public class TestCountDownLatch {

    public static void main(String[] args) {
        //计数值（count）实际上就是闭锁需要等待的线程数量。
        final CountDownLatch cdl = new CountDownLatch(6);  //闭锁
        LatchDemo ld = new LatchDemo(cdl);

        long start = System.currentTimeMillis();

        for (int i=0; i<5; i++){
            new Thread(ld).start();
        }
        /*主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。
            这样主线程的操作就会在这个方法上阻塞，直到其他线程完成各自的任务。
            这也是与CountDownLatch的第一次交互,即主线程等待其他线程*/
        try {
            cdl.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();

        System.out.println("耗费时间为:"+(end-start));
    }
}

class LatchDemo implements Runnable{
    /*
    * 其他几个线程必须引用闭锁对象,因为他们需要通知CountDownLatch对象，
    * 他们已经完成了各自的任务.通知机制便是通过下面的latch.countDown()
    * 当count的值为0时等待的主线程便会恢复自己的任务
    * */
    private CountDownLatch latch;
    public LatchDemo(CountDownLatch latch){
        this.latch = latch;
    }

    @Override
    public void run() {
        synchronized (this){
            try {
                for (int i=0; i<50000; i++){
                    if(i%2 == 0){
                        System.out.println(i);
                    }
                }
            } finally {
                latch.countDown();  //递减1
            }
        }
    }
}


/**
 * CyclicBarrier让一组线程到达一个屏障（也可以叫同步点）时被阻塞，直到最后一个线程到达屏障时，
 *                  屏障才会开门，所有被屏障拦截的线程才会继续干活
 */
class TestCyclicBarrier{

    static CyclicBarrier cb = new CyclicBarrier(6);  //参数代表屏幕拦截的数量
//      static CyclicBarrier cb = new CyclicBarrier(2,new CB());  //构造函数的第二个参数是在所有子线程都到达屏障时先执行此
    public static void main(String[] args) {

         new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        cb.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    System.out.println(1);
                }
            }).start();
        try {
            cb.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
        System.out.println(2);
    }
}

class CB implements Runnable{

    @Override
    public void run() {
        System.out.println(4);
    }

}

/**
 * CyclicBarrier和CountDownLatch区别:
 *    cdl的的计数器数量count不可变, countCyclicBarrier的计数器可以使用reset() 方法重置
 *    CyclicBarrier还提供其他有用的方法，比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。
 *    CyclicBarrier 到达屏障是通过await()来实现的(即操纵计数器数值),CountDownLatch是通过CounrDown()来控制计数器数量
 */